/**
 * 
 */
package com.sj.szxy.genetic.algorithm.courseschedule;

import java.util.HashMap;


/**
 * @author Yi Ping
 * @date 2018年4月3日 下午9:46:48 
 * @since 1.0.0
 *
 */
public class Timetable {
	
	private final HashMap<Integer, Room> rooms;
	private final HashMap<Integer, Professor> professors;
	private final HashMap<Integer, Module> modules;
	private final HashMap<Integer, Group> groups;
	private final HashMap<Integer, Timeslot> timeslots;
	private Class classes[];
	
	private int numClasses =0;
	
	public Timetable() {
		this.rooms = new HashMap<>();
		this.professors = new HashMap<>();
		this.modules = new HashMap<>();
		this.groups = new HashMap<>();
		this.timeslots = new HashMap<>();
	}
	
	public Timetable(Timetable cloneable ) {
		this.rooms = cloneable.getRooms();
		this.professors = cloneable.getProfessors();
		this.modules = cloneable.getModules();
		this.groups = cloneable.getGroups();
		this.timeslots = cloneable.getTimeslots();
	}

	/**
	 * add new room
	 * @param roomId
	 * @param roomNumber
	 * @param capacity
	 */
	public void addRoom(int roomId, String roomNumber, int capacity) {
		this.rooms.put(roomId, new Room(roomId, roomNumber, capacity));
	}
	
	public void addProfessor(int professorId, String professorName) {
		this.professors.put(professorId,new Professor(professorId, professorName));
	}
	
	public void addModule(int moduleId, String moduleCode, String module, int professorIds[]) {
		this.modules.put(moduleId, new Module(moduleId, moduleCode, module, professorIds));
	}
	
	public void addGroup(int groupId, int groupSize, int moduleIds[]) {
		this.groups.put(groupId, new Group(groupId, groupSize, moduleIds));
		this.numClasses = 0;
	}
	
	public void addTimeslot(int timeslotId, String timeslot) {
		this.timeslots.put(timeslotId, new Timeslot(timeslotId, timeslot));
	}
	
	/**
	 * create classes using individual's chromosome
	 */
	public void createClasses(Individual individual) {
		Class classes[] = new Class[this.getNumClasses()];
		int chromosome[] = individual.getChromosome();
		int chromosomePos = 0;
		int classIndex = 0;
		
		for(Group group: this.groups.values()) {
			int moduleIds[] = group.getModuleIds();
			for(int moduleId: moduleIds) {
				classes[classIndex] = new Class(classIndex, group.getGroupId(),moduleId);
				
				classes[classIndex].addTimeslot(chromosome[chromosomePos]);
				chromosomePos++;
				classes[classIndex].setRoomId(chromosome[chromosomePos]);
				chromosomePos ++;
				classes[classIndex].addProfessor(chromosome[chromosomePos]);
				chromosomePos++;
				
				classIndex ++;
				
			}
		}
		
		this.classes = classes;
	}
	
	public Room getRandomRoom() {
		Object[] roomsArray = this.rooms.values().toArray();
		Room room = (Room) roomsArray[(int) (roomsArray.length*Math.random())];
		return room;
	}
	
	public int[] getGroupModules(int groupId) {
		return this.groups.get(groupId).getModuleIds();
	}
	
	public Group getGroup(int groupId) {
		return this.groups.get(groupId);
	}
	
	
	/**
	 * @return
	 */
	public Group[] getGroupsAsArray() {
		return this.groups.values().toArray(new Group[this.groups.size()]);
	}
	
	public Timeslot getTimeslot(int timeslotId) {
		return this.timeslots.get(timeslotId);
	}
	
	public Timeslot getRandomTimeslot() {
		Timeslot[] array = this.timeslots.values().toArray(new Timeslot[this.timeslots.size()]);
		return array[(int) (array.length* Math.random())];
	}
	
	

	public Class[] getClasses() {
		return classes;
	}

	/**
	 * 获取并设置课程总数
	 * @return
	 */
	public int getNumClasses() {
		if(this.numClasses>0) {
			return this.numClasses;
		}
		
		int numClasses = 0;
		for(Group group: this.groups.values()) {
			numClasses +=group.getModuleIds().length;
		}
		this.numClasses = numClasses;
		
		return this.numClasses;
	}
	
	public int calcClashes() {
		int clashes = 0;
		for(Class classA: this.classes) {
			//Check room capacity
			int roomCapacity = this.rooms.get(classA.getRoomId()).getCapacity();
			int groupSize = this.getGroup(classA.getGroupId()).getGroupSize();
			if(roomCapacity < groupSize)
				clashes++;
			
			// check room is taken
			for(Class classB: this.classes) {
				if(classA.getRoomId() ==classB.getRoomId() 
						&& classA.getTimeslotId() == classB.getTimeslotId()
						&& classA.getClassId() != classB.getClassId()) 
					clashes++; break;
				
			}
			//check if professor is available
			for(Class classB: this.classes) {
				if(classA.getProfessorId() == classB.getProfessorId()
						&& classA.getTimeslotId()== classB.getTimeslotId()
						&& classA.getClassId() != classB.getClassId())
					clashes++; break;
			}
		}
		
		return clashes;

	}
	
	public void setClasses(Class[] classes) {
		this.classes = classes;
	}


	public void setNumClasses(int numClasses) {
		this.numClasses = numClasses;
	}

	public HashMap<Integer, Room> getRooms() {
		return rooms;
	}
	
	public Room getRoom(int roomId) {
		return rooms.get(roomId);
	}
	
	public HashMap<Integer, Professor> getProfessors() {
		return professors;
	}

	public Professor getProfessor(int professorId) {
		return professors.get(professorId);
	}
	
	public HashMap<Integer, Module> getModules() {
		return modules;
	}
	
	public Module getModule(int moduleId) {
		return modules.get(moduleId);
	}
	public HashMap<Integer, Group> getGroups() {
		return groups;
	}

	public HashMap<Integer, Timeslot> getTimeslots() {
		return timeslots;
	}

	
	
	
}
